package com.haoqizhe.kernel.web.result;

import cn.hutool.core.util.StrUtil;
import com.haoqizhe.kernel.commons.enums.BusinessExceptionEnum;
import com.haoqizhe.kernel.commons.enums.ResultCode;
import com.haoqizhe.kernel.commons.exceptions.BusinessException;
import com.haoqizhe.kernel.commons.util.ByteUtils;
import com.haoqizhe.kernel.commons.util.RequestContextUtil;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;

import javax.validation.ConstraintViolationException;
import java.util.Date;

/**
 * 默认全局错误返回结果
 * 备注：该返回信息是spring boot的默认异常时返回结果{@link }，目前也是我们服务的默认返回结果
 *
 * @author haoqizhe.li
 * @date 2018/4/2 22:38
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ApiModel(value = "异常返回信息")
public class DefaultErrorResult implements IResult {
    private static final long serialVersionUID = 1899083570489722793L;

    /**
     * HTTP响应状态码 {@link HttpStatus}
     */
    @ApiModelProperty(value = "HTTP响应状态码 ")
    private Integer status;

    /**
     * HTTP响应状态码的英文提示
     */
    @ApiModelProperty(value = "HTTP响应状态码的英文提示")
    private String error;

    /**
     * 异常堆栈的精简信息
     */
    @ApiModelProperty(value = "异常提示信息")
    private String message;

    /**
     * 我们系统内部自定义的返回值编码，它是对错误更加详细的编码
     * <p>
     * 备注：spring boot默认返回异常时，该字段为null
     */
    @ApiModelProperty(value = "异常返回值编码")
    private Integer code;

    /**
     * 调用接口路径
     */
    @ApiModelProperty(value = "调用接口路径")
    private String path;

    /**
     * 异常的名字
     */
    @ApiModelProperty(value = "主键")
    private String exception;

    /**
     * 异常的错误传递的数据
     */
    @ApiModelProperty(value = "异常的错误传递的数据")
    private Object data;

    /**
     * 时间戳
     */
    @ApiModelProperty(value = "时间戳")
    private Date timestamp;

    public static DefaultErrorResult failure(ResultCode resultCode, Throwable e, HttpStatus httpStatus, Object errors) {
        DefaultErrorResult result = DefaultErrorResult.failure(resultCode, e, httpStatus);
        result.setData(errors);
        return result;
    }

    public static DefaultErrorResult failure(ResultCode resultCode, Throwable e, HttpStatus httpStatus) {

        String errMsg = e.getMessage();
        if (!ByteUtils.isChinese(errMsg) ||
                e instanceof BindException ||
                e instanceof ConstraintViolationException) {
            errMsg = resultCode.message().replaceAll("\\{}", "");
        }

        DefaultErrorResult result = new DefaultErrorResult();
        result.setCode(resultCode.code());
        result.setMessage(errMsg);
        result.setStatus(httpStatus.value());
        result.setError(httpStatus.getReasonPhrase());
        result.setException(e.getClass().getName());
        String path = RequestContextUtil.getRequest().getRequestURI();
        result.setPath(path);
        result.setTimestamp(new Date());
        return result;
    }

    public static DefaultErrorResult failure(BusinessException e) {
        BusinessExceptionEnum ee = BusinessExceptionEnum.getByEClass(e.getClass());
        if (ee != null) {
            return DefaultErrorResult.failure(ee.getResultCode(), e, ee.getHttpStatus(), e.getData());
        }

        DefaultErrorResult defaultErrorResult = DefaultErrorResult.failure(e.getResultCode() == null ? ResultCode.SYSTEM_INNER_ERROR : e.getResultCode(), e, HttpStatus.INTERNAL_SERVER_ERROR, e.getData());
        if (StrUtil.isNotEmpty(e.getMessage())) {
            defaultErrorResult.setMessage(e.getMessage());
        }
        return defaultErrorResult;
    }
}
